//
//  SFCAPRPool.m
//  SVNForCocoa
//
//  Created by Jeremy Pereira on 06/11/2013.
//  Copyright (c) 2013 Jeremy Pereira. All rights reserved.
//

#import "SFCAPRPool.h"
#import <apr_pools.h>
#import "SFCError.h"

@interface SFCAPRPool ()

-(id) initWithParent: (SFCAPRPool*) parent
               error: (NSError* __autoreleasing*) error;

@property (nonatomic, weak) SFCAPRPool* parent;

@property (nonatomic, assign) apr_pool_t* aprPool;

@end

@implementation SFCAPRPool
{
    NSMutableSet* childPools;
}
@synthesize aprPool = _aprPool;
@synthesize parent = _parent;

-(id) initWithParent: (SFCAPRPool*) parent
               error: (NSError* __autoreleasing*) error
{
    self = [super init];
    if (self != nil)
    {
		apr_pool_t* aprParent = [parent aprPool]; // will be NULL if parent is nil
        childPools = [[NSMutableSet alloc] init];
		apr_status_t status = apr_pool_create(&_aprPool, aprParent);
        if (status != APR_SUCCESS)
        {
			if (error != nil)
            {
                *error = [SFCError aprError: status];
            }
            self = nil;
        }
        else
        {
            [parent addChild: self];
        }
    }
    return self;
}

-(id) init
{
    return [self initWithParent: nil error: NULL];
}

-(void) dealloc
{
    [self destroy];
}

+(SFCAPRPool*) makePoolWithParent: (SFCAPRPool*) parent
                            error: (NSError* __autoreleasing*) error
{
	return [[[self class] alloc] initWithParent: parent error: error];
}

-(SFCAPRPool*) newChild
{
    return [[self class] makePoolWithParent: self error: nil];
}

-(bool) hasChild: (SFCAPRPool*) aPool
{
    return [childPools containsObject: aPool];
}

-(void) clear
{
    if ([self aprPool] != NULL)
    {
        /*
         *  If we don't destroy the subpools ourselves, the APR call will do it and
         *  leave our objects with dangling apr_pool_t pointers.
         */
        for (SFCAPRPool* child in [childPools copy])
        {
            [child destroy];
        }
        [childPools removeAllObjects];
        apr_pool_clear([self aprPool]);

    }
}

-(void) destroy
{
    if ([self aprPool] != NULL)
    {
        [self clear];
        apr_pool_destroy([self aprPool]);
        [self setAprPool: NULL];
        [[self parent] removeChild: self];
    }
}

-(void) addChild: (SFCAPRPool*) newChild
{
    if ([newChild parent] != nil)
    {
        @throw [NSException exceptionWithName: @"SFCAddChild"
                                       reason: @"Cannot add a child that already has a parent"
                                     userInfo: nil];
    }
    [childPools addObject: newChild];
    [newChild setParent: self];
}

-(void) removeChild: (SFCAPRPool*) childToGo
{
    if ([self hasChild: childToGo])
    {
        [childPools removeObject: childToGo];
        [childToGo setParent: nil];
    }
}

-(bool) isAlive
{
    return [self aprPool] != NULL;
}

@end
